#ifndef MCGPP_GRAPH_IO_H
#define MCGPP_GRAPH_IO_H

#include <fstream>
#include <filesystem>
#include <iomanip>
#include "graph.h"
#include "timer.h"
#include "macros.h"
#include "context.h"

namespace mcgpp {
  namespace io {
    //创建目录，可以递归
    bool createDirectories(const std::string& path) {
      try {
        if (!std::filesystem::exists(path)) {
          std::filesystem::create_directories(path);
          std::cout << "Directories created successfully: " << path << std::endl;
        } else {
          std::cout << "Directory already exists: " << path << std::endl;
        }
        return true;
      } catch (const std::filesystem::filesystem_error& e) {
        std::cerr << "Error creating directories: " << e.what() << std::endl;
        return false;
      }
    }
    static bool getNextLine(std::ifstream &file, std::string &line) {
      bool success = false;
      do {
        success = static_cast<bool>(std::getline(file, line));
        // skip any comments
      } while (success && line[0] == '%');
      return success;
    }
    //快读
    class FastIO {
    public:
      FastIO(const std::string &filename) {
        file = fopen(filename.c_str(), "r");
        ch = 'z';
        p1 = in;
        p2 = in;
      }

      ~FastIO() {
        fclose(file);
      }

      //每一行读取前设置
      void reset(){
        isEnd = false;
      }
      bool readFinish(){
        return isEnd;
      }
      template<typename type>
      inline void readNum(type &x) {
        do {
          ch = getchar();
        }while(ch == ' ') ;

        if(ch == EOF || ch == '\n' || ch == '\r')
          isEnd = true;

        x = 0;
        while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
        if(ch == EOF || ch == '\n' || ch == '\r')
          isEnd = true;
      }
      //确保一定会读到一个数字的时候使用
      template<typename type>
      inline void readNum2(type &x) {
        do {
          ch = getchar();
        }while(!isdigit(ch));
        x = 0;
        while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();

      }
      inline char getchar() {
        return p1 == p2 && (p2 = (p1 = in) + fread(in, 1, SIZE, file), p1 == p2) ? EOF : *p1++;
      }

      bool isEnd;
      FILE *file;
      char *p1, *p2, ch;
      char in[1 << 20];//输入缓冲区
      int32_t SIZE = 1 << 20;
    };

    static inline void readGRHeader(std::ifstream &file, IDType &num_nodes,
                                    IDType &num_edges) {
      std::string line;
      getNextLine(file, line);
      std::stringstream sstream(line);
      sstream >> num_nodes >> num_edges;

      LOG << "num nodes:" << num_nodes;
      LOG << "num edges:" << num_edges;


    }

    static inline ds::GenericGraph createGraphFromFile2(const std::string &filename,
                                                       const PartitionID num_parts) {
      IDType num_nodes;
      IDType num_edges;
      Vec<IDType> index_vector;//记录每条边的pin在edge_vector的起始索引，即[index_vector[id],index_vector[id+1])
      Vec<IDType> edge_vector;//记录每条边的pin，所有边的所有pin全部存放在edge_vector

      std::ifstream file(filename);
      if (!file.is_open()) {
        LOG << filename;
        ERROREXIT("file not Found!");
      }

      readGRHeader(file, num_nodes, num_edges);
      index_vector.reserve(static_cast<size_t>(num_edges) +  /*sentinel*/ 1);
      index_vector.push_back(edge_vector.size());
      //读取每条边
      std::string line;
      for (int i = 0; i < num_nodes; ++i) {
        getNextLine(file, line);
        std::stringstream ss(line);
        IDType n_id;
        while (ss >> n_id) {
          --n_id;//图里面的顶点下标是从1开始的
          //转换成一条边 i,n_id
          if (i < n_id) {
            //防止重复
            edge_vector.emplace_back(i);
            edge_vector.emplace_back(n_id);
            //每条边i的起点index_vector[i],终点index_vector[i+1]
            index_vector.push_back(edge_vector.size());
          }
        }
      }
      DBG << "index vector size:" << index_vector.size();

      file.close();

      return ds::GenericGraph(num_nodes, num_edges, index_vector[num_edges], index_vector.data(),
                              edge_vector.data());

    }


    static inline ds::GenericGraph createGraphFromFile(const std::string &filename,
                                                       const PartitionID num_parts) {
      IDType num_nodes;
      IDType num_edges;
      Vec<IDType> index_vector;//记录每条边的pin在edge_vector的起始索引，即[index_vector[id],index_vector[id+1])
      Vec<IDType> edge_vector;//记录每条边的pin，所有边的所有pin全部存放在edge_vector


      FastIO rd(filename);
      rd.reset();//第一行末尾可能还有值
      rd.readNum(num_nodes);//读取顶点
      rd.readNum(num_edges);//读取边数
      while(!rd.readFinish()){
        IDType n_id;
        rd.readNum(n_id);
      }

      LOG << "num nodes:" << num_nodes;
      LOG << "num edges:" << num_edges;

      index_vector.reserve(static_cast<size_t>(num_edges) +  /*sentinel*/ 1);
      index_vector.push_back(edge_vector.size());
      //读取每条边
      for (int i = 0; i < num_nodes; ++i) {

        IDType n_id;
        rd.reset();
        while(true){
          n_id = -1;
          rd.readNum(n_id);
          if(n_id > 0){
            //有效
//            std::cout<<n_id<<" ";
            --n_id;//图里面的顶点下标是从1开始的
            //转换成一条边 i,n_id
            if (i < n_id) {
              //防止重复
              edge_vector.emplace_back(i);
              edge_vector.emplace_back(n_id);
              //每条边i的起点index_vector[i],终点index_vector[i+1]
              index_vector.push_back(edge_vector.size());
            }
          }
          if(rd.readFinish())
            break;
        }
//        LOG<<"";

      }
      DBG << "index vector size:" << index_vector.size();

      return ds::GenericGraph(num_nodes, num_edges, index_vector[num_edges], index_vector.data(),
                              edge_vector.data());

    }



    //创建正常的邻接链表
    static inline void readGraph(const std::string &filename, int &nodeNum, int &edgeNum, std::vector<std::vector<int>> &adj_list) {
      std::ifstream file(filename);
      if (!file.is_open()) {
        LOG << filename;
        ERROREXIT("file not Found!");
      }
      std::string line;
      std::getline(file, line);
      std::stringstream ss(line);
      ss >> nodeNum >> edgeNum;
      LOG<<"node num:"<<nodeNum;
      LOG<<"edge num:"<<edgeNum;

      adj_list.resize(nodeNum);
      int ans = 0;
      for (int i = 0; i < nodeNum; ++i) {
        std::getline(file, line);
        std::stringstream ss(line);
        int v;
        while (ss >> v) {
          --v;
          adj_list[i].emplace_back(v);
        }
        ans += adj_list[i].size();

      }

      file.close();

    }

    //从0开始的
    static inline void readPartitionFile2(const std::string &filename, std::vector<IDType> &partition) {
      std::ifstream file(filename);
      if (file) {
        int num_part, node;
        file >> num_part;
        for (int i = 0; i < num_part; ++i) {
          file >> node;
          partition[node] = 1;
        }
        file.close();
      } else {
        ERROREXIT("File not found.");
      }
    }
    //快速读版本
    static inline void readPartitionFile(const std::string &filename, std::vector<IDType> &partition) {
      FastIO file(filename);
      int num_part;
      file.readNum2(num_part);
      for(int i=0;i<num_part;++i){
        int node;
        file.readNum2(node);
        partition[node] = 1;
      }
    }

    //保存划分结果到csv文件？
    static inline void savePartitionFile(const ds::GenericGraph & graph) {
//      std::string instance_name =  Context::instance().instance_file.substr(0,Context::instance().instance_file.find('.'));

      //创建输出目录
      createDirectories(Context::instance().output_dir);

      std::string filename = Context::instance().output_dir + PATH_SEPARATOR_STR +
              Context::instance().instance_name + ".csv";
      std::ofstream file(filename, std::ios::out | std::ios::app);//追加的方式写入csv
      //日期 随机数 初始解 最优结果 找到最优解的时间 总运行时间
      file << Timer::instance().getData() << "," << Context::instance().seed << ",";
      file << std::fixed << std::setprecision(10) << Context::instance().partitionResult.init_conductance << ",";
      file << std::fixed << std::setprecision(10) << Context::instance().partitionResult.conductance << ",";
      file << std::fixed << std::setprecision(3) << Context::instance().partitionResult.best_time << ","
           << Context::instance().partitionResult.total_time<<std:: endl;
      file.close();
    }
  }
}
#endif //MCGPP_GRAPH_IO_H
